package com.tz.platform.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

@Repository
public abstract class BaseDaoImpl<T> implements IDao<T> {

	protected transient final Logger log = LoggerFactory.getLogger(getClass());

	protected SessionFactory sessionFactory;
	
	protected Class<T> entityClass;
	
	@Autowired
	public void setSessionFactory(final SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}
	
	public abstract Class<T> getEntityClass();

	@SuppressWarnings("unchecked")
	public Class<T> getEntityClass(Class<?> daoClass) {
		Type t = daoClass.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}
		return entityClass;
	}
	
	@Override
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void save(final T entity) {
		Assert.notNull(entity);
		getSession().save(entity);
	}

	@Override
	public void saveOrUpdate(final T entity){
		Assert.notNull(entity);
		try {
			getSession().saveOrUpdate(entity);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public void removeById(final Serializable id) {
		getSession().delete(get(id));
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public T get(final Serializable id) {
		return (T) getSession().get(getEntityClass(), id);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public T findUnique(final String hql, final Object... values) {
		try {
			return (T) createQueryValues(hql, values).uniqueResult();
		} catch (HibernateException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	@Override
	public void executeByHql(final String hql, final Object... values){
		Assert.hasText(hql);
		Query q = createQueryValues(hql, values);
		q.executeUpdate();
	}
	
	@Override
	public void executeBySql(final String sql, final Object... values){
		Query query = getSession().createSQLQuery(sql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		query.executeUpdate();
	}
	
	@Override
	public String getMaxValue(final String hql, final Object... values){
		String r = (String)createQueryValues(hql).uniqueResult(); 
		return r;
	}
	
	/**
	 * 根据sql查询总数
	 * @param sql
	 * @param values
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public int getCountBySqlValues(final String sql,final Object... values){
		Query query = createQuerySqlValues("select count(1) from ("+sql+") as sqlCount", values);
		List<Map> list = query.list();
		return Integer.parseInt(list.get(0).get("count(1)").toString());
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> getAll() {
		return this.createCriteria().list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<T> find(final String hql, final Object... values) {
		Assert.hasText(hql);
		return createQueryValues(hql, values).list();
	}
	
	
	

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findPaged(final String ql, final int pageNo, final int pageSize, final Object... values) {

		Assert.isTrue(pageNo >= 1, "pageNo should start from 1");
		// Count查询
		int startIndex;
		Query query = createQueryValues(ql, values);
		query.getNamedParameters();
		ScrollableResults scrollableResults = query.scroll();
		scrollableResults.last();
		startIndex = (pageNo - 1) * pageSize;
		List<T> list = query.setFirstResult(startIndex).setMaxResults(pageSize).list();
		return list;
	}

	
	
	
	

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<Map> findByNQL(final String sql,final Object... values){
		Query query = getSession().createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		List<Map> list = query.list();
		return list;
	}
	
	
	@Override
	public void clear() {
		getSession().clear();
	}
	
	/**
	 * 根据SQL查询结果
	 * @param hql
	 * @param values
	 * @return
	 */
	private Query createQuerySqlValues(final String sql, final Object... values) {
		Assert.hasText(sql);
		Query query = getSession().createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}
	
	/**
	 * 根据传入的条件查询
	 * @param hql
	 * @param values
	 * @return
	 */
	private Query createQueryValues(final String hql, final Object... values) {
		Assert.hasText(hql);
		Query query = getSession().createQuery(hql);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}
	
	
	
	@SuppressWarnings("deprecation")
	public void refresh(T entity) {
		getSession().flush();
		this.getSession().refresh(entity, LockMode.UPGRADE);
	}

	private Criteria createCriteria(final Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(getEntityClass());
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}
	
	
	
}